package cn.net.shuxing.yifu.common.service;

import cn.net.shuxing.yifu.common.bean.CoinType;
import cn.net.shuxing.yifu.common.bean.ContentAd;
import cn.net.shuxing.yifu.common.bean.KLineData;
import cn.net.shuxing.yifu.common.bean.UserDealHistory;
import cn.net.shuxing.yifu.common.constant.DealScene;
import cn.net.shuxing.yifu.common.constant.DealType;
import cn.net.shuxing.yifu.common.constant.KLineCommonConst;
import cn.net.shuxing.yifu.common.constant.KLineConst;
import cn.net.shuxing.yifu.common.dto.DealRecordDto;
import cn.net.shuxing.yifu.common.dto.KLineDto;
import cn.net.shuxing.yifu.common.dto.KLinePartTwo;
import cn.net.shuxing.yifu.common.mapper.ContentAdMapper;
import cn.net.shuxing.yifu.common.mapper.KLineDataMapper;
import cn.net.shuxing.yifu.common.util.*;
import com.github.pagehelper.PageHelper;
import lombok.val;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class KLineDataService extends BaseService<KLineData, KLineDataMapper> {
    @Autowired
    private CoinTypeService coinTypeService;

    @Autowired
    private UserDealHistoryService userDealHistoryService;

    @Autowired
    private JedisUtil jedisUtil;

    @Autowired
    private CoinRatioService coinRatioService;

    /**
     * 获取上次计算的时间
     *
     * @param minuteUnit 时间区间K线图
     * @return
     */
    public KLineCommonConst getKLineCommon(Integer minuteUnit) {
                KLineCommonConst commonConst = new KLineCommonConst();
        Integer type = 0;
        String s = "";
        long lastSecond = 0;
        if (minuteUnit == 1) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMinutesOne());
        }
        if (minuteUnit == 5) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMinutesFive());
            type = KLineConst.MINUTES_FIVE;
        }
        if (minuteUnit == 15) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMinutesfifteen());
            type = KLineConst.MINUTES_FIFTEEN;
        }
        if (minuteUnit == 30) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMinutesThirty());
            type = KLineConst.MINUTES_THIRTY;
        }
        if (minuteUnit == 60) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeHourOne());
            type = KLineConst.HOUR_ONE;
        }
        if (minuteUnit == 120) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeHourTwo());
            type = KLineConst.HOUR_TWO;
        }
        if (minuteUnit == 240) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeHourFour());
            type = KLineConst.HOUR_FOUR;
        }
        if (minuteUnit == 480) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeHourEight());
            type = KLineConst.HOUR_EIGHT;
        }
        if (minuteUnit == 1440) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeDayOne());
            type = KLineConst.DAY_ONE;
        }
        if (minuteUnit == 10080) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeDaySeven());
            type = KLineConst.DAY_SEVEN;
        }
        if (minuteUnit == 43200) {
            s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMonthOne());
            type = KLineConst.MONTH_ONE;
        }

        if (!StringUtils.hasText(s)) {
//            Calendar now = Calendar.getInstance();
            Calendar calendar = Calendar.getInstance();
            calendar.clear();
//            calendar.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DATE));
            calendar.set(2019, 1, 1);
            lastSecond  = calendar.getTimeInMillis();
            commonConst.setLastSecond(lastSecond);
        }else {
            commonConst.setLastSecond(Long.parseLong(s));
        }
        commonConst.setType(type);
        return commonConst;
    }


    public void setKLineEndSecond(Integer minuteUnit, long time) {
        String s = time + "";
        if (minuteUnit == 1) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeMinutesOne(), s);
        }
        if (minuteUnit == 5) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeMinutesFive(), s);
        }
        if (minuteUnit == 15) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeMinutesfifteen(), s);
        }
        if (minuteUnit == 30) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeMinutesThirty(), s);
        }
        if (minuteUnit == 60) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeHourOne(), s);
        }
        if (minuteUnit == 120) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeHourTwo(), s);
        }
        if (minuteUnit == 240) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeHourFour(), s);
        }
        if (minuteUnit == 480) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeHourEight(), s);
        }
        if (minuteUnit == 1440) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeDayOne(), s);
        }
        if (minuteUnit == 10080) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeDaySeven(), s);
        }
        if (minuteUnit == 43200) {
            jedisUtil.set(RedisKeyCreator.kLineEndTimeMonthOne(), s);
        }
    }

    public void calculateLastKLineData(Integer minuteUnit, Integer coinTypeId, LocalDateTime startDateTime, long second) {
        KLineCommonConst kLineCommon = getKLineCommon(minuteUnit);
        Integer type = kLineCommon.getType();
        Long lastSecond = kLineCommon.getLastSecond();
        CommonExample example = new CommonExample(KLineData.class);
        example.equals("coinTypeId", coinTypeId);
        example.equals("type", type);
        example.setOrderByClause("id DESC");
        List<KLineData> kLineDataList = getsByExample(example);
        if (kLineDataList != null && !kLineDataList.isEmpty()) {
            KLineData kLineData = kLineDataList.get(0);
            KLineData newKLineData = new KLineData();
            newKLineData.setCreateTime(startDateTime);
//            kLineData.setId(kLineData.getId() + 1);
            newKLineData.setCreateSecond(second);
//            LocalDateTime time = kLineData.getTime();
            Instant instant = Instant.ofEpochMilli(lastSecond);
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime time = LocalDateTime.ofInstant(instant, zone);
            if (type == 0)
                time.plusMinutes(1);
            if (type == 1)
                time.plusMinutes(5);
            if (type == 2)
                time.plusMinutes(15);
            if (type == 3)
                time.plusMinutes(30);
            if (type == 4)
                time.plusHours(1);
            if (type == 5)
                time.plusHours(2);
            if (type == 6)
                time.plusHours(4);
            if (type == 7)
                time.plusHours(8);
            if (type == 8)
                time.plusDays(1);
            if (type == 9)
                time.plusDays(7);
            if (type == 10)
                time.plusMonths(1);
            newKLineData.setTime(time);
            newKLineData.setOpenPrice(kLineData.getOpenPrice());
            newKLineData.setClosePrice(kLineData.getClosePrice());
            newKLineData.setHighestPrice(kLineData.getHighestPrice());
            newKLineData.setLowestPrice(kLineData.getLowestPrice());
            newKLineData.setGain(kLineData.getGain());
            newKLineData.setTotalDealCount(kLineData.getTotalDealCount());
            newKLineData.setVolume(kLineData.getVolume());
            newKLineData.setMacd(kLineData.getMacd());
            newKLineData.setDiff(kLineData.getDiff());
            newKLineData.setDea(kLineData.getDea());
            newKLineData.setCoinTypeId(kLineData.getCoinTypeId());
            newKLineData.setType(kLineData.getType());
            insert(newKLineData);
        }
    }

    public void calculateKLineDataByMinuteUnit(Integer minuteUnit) {
        List<CoinType> all = coinTypeService.getAll();
        if (all != null) {
            for (CoinType coinType : all) {
                Integer coinTypeId = coinType.getId();
                KLineCommonConst kLineCommon = getKLineCommon(minuteUnit);
                Long lastSecond = kLineCommon.getLastSecond();
                long nowSecend = System.currentTimeMillis();
                setKLineEndSecond(minuteUnit, nowSecend);
                int nowMinute = (int) Math.floor(nowSecend / 60000);
                int lastMinute = (int) Math.floor(lastSecond / 60000);
                int count = nowMinute - lastMinute;
                for (int j = count; j > 0; j--) {
                    long newlastSecond = lastSecond + minuteUnit * 1000;
                    setKLineEndSecond(minuteUnit,newlastSecond);
                    String s = jedisUtil.get(RedisKeyCreator.kLineEndTimeMinutesOne());
                    LocalDateTime startDateTime = new Date(lastSecond).toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
                    startDateTime = startDateTime.plusMinutes(0 - minuteUnit * j);
                    LocalDateTime tempEndTime = startDateTime.plusMinutes(0 - minuteUnit * (j - 1));
                    TimeExample example = new TimeExample(UserDealHistory.class);
                    example.equals("coinTypeId", coinTypeId);
                    example.equals("dealScene", DealScene.NONE);
                    Example.Criteria criteria = example.createCriteria();
                    criteria.orEqualTo("dealType", DealType.HANG_BUY);
                    criteria.orEqualTo("dealType", DealType.HANG_SALE);
                    example.and(criteria);
                    example.between("createTime", tempEndTime, startDateTime);
                    example.setOrderByClause("id ASC");
                    List<UserDealHistory> dealHistoryList = userDealHistoryService.getsByExample(example);
                    BigDecimal lowestPrice = new BigDecimal(0);
                    BigDecimal highestPrice = new BigDecimal(0);
                    BigDecimal lastTimeHighestPrice = new BigDecimal(0);
                    BigDecimal totalDealCount = new BigDecimal(0);
                    BigDecimal diff = new BigDecimal(0);
                    BigDecimal macd = new BigDecimal(0);
                    BigDecimal dea = new BigDecimal(0);
                    BigDecimal ema12 = new BigDecimal(0);
                    BigDecimal ema26 = new BigDecimal(0);
                    if (dealHistoryList != null && !dealHistoryList.isEmpty()) {
                        KLineData kLineData = new KLineData();
                        kLineData.setOpenPrice(dealHistoryList.get(0).getDealAliveCoinCount());
                        BigDecimal momentColsePrice = dealHistoryList.get(dealHistoryList.size() - 1).getDealAliveCoinCount();
                        kLineData.setClosePrice(momentColsePrice);
                        for (int k = 0; k < dealHistoryList.size(); k++) {
                            //第一张图
                            BigDecimal price = dealHistoryList.get(k).getSinglePrice();
                            if (price.compareTo(lowestPrice) < 0) {
                                lowestPrice = price;
                            }
                            if (price.compareTo(highestPrice) > 0) {
                                highestPrice = price;
                            }
                            totalDealCount = totalDealCount.add(dealHistoryList.get(k).getDealAliveCoinCount());
                        }
                        if (j == 0) {
                            kLineData.setGain(new BigDecimal(0));
                            ema12 = (ema12.multiply(new BigDecimal(11)).divide(new BigDecimal(13), 8, BigDecimal.ROUND_HALF_UP)).add(momentColsePrice.multiply(new BigDecimal(2).divide(new BigDecimal(13))));
                            ema26 = (ema26.multiply(new BigDecimal(25)).divide(new BigDecimal(27), 8, BigDecimal.ROUND_HALF_UP)).add(momentColsePrice.multiply(new BigDecimal(2).divide(new BigDecimal(27))));
                            dea = (dea.multiply(new BigDecimal(8)).divide(new BigDecimal(10))).add(diff.multiply(new BigDecimal(2).divide(new BigDecimal(10))));
                        } else {
                            kLineData.setGain(lastTimeHighestPrice.subtract(highestPrice).divide(highestPrice, 8, BigDecimal.ROUND_HALF_UP));
                        }
                        lastTimeHighestPrice = highestPrice;
                        kLineData.setLowestPrice(lowestPrice);
                        kLineData.setHighestPrice(highestPrice);
                        kLineData.setTotalDealCount(totalDealCount);
                        //第二张图
                        kLineData.setVolume(totalDealCount);
                        //第三张图
                        diff = ema12.subtract(ema26);
                        macd = diff.subtract(diff);
                        kLineData.setMacd(macd);
                        kLineData.setDiff(diff);
                        kLineData.setDea(dea);
                        Integer type = kLineCommon.getType();
                        kLineData.setType(type);
                        Instant instant = Instant.ofEpochMilli(lastSecond);
                        ZoneId zone = ZoneId.systemDefault();
                        LocalDateTime time = LocalDateTime.ofInstant(instant, zone);
                        if (type == 0)
                            time.plusMinutes(1);
                        if (type == 1)
                            time.plusMinutes(5);
                        if (type == 2)
                            time.plusMinutes(15);
                        if (type == 3)
                            time.plusMinutes(30);
                        if (type == 4)
                            time.plusHours(1);
                        if (type == 5)
                            time.plusHours(2);
                        if (type == 6)
                            time.plusHours(4);
                        if (type == 7)
                            time.plusHours(8);
                        if (type == 8)
                            time.plusDays(1);
                        if (type == 9)
                            time.plusDays(7);
                        if (type == 10)
                            time.plusMonths(1);
                        kLineData.setTime(time);
                        insert(kLineData);
                    } else {
                        calculateLastKLineData(minuteUnit, coinTypeId, startDateTime, nowSecend);
                    }
                }
            }
        }
    }

    public List<KLineData> getKLineDataTwo(Integer minuteUnit, Integer coinTypeId, Integer pageNum) {
        PageHelper.startPage(pageNum, 50);
        CommonExample example = new CommonExample(KLineData.class);
        KLineCommonConst kLineCommon = getKLineCommon(minuteUnit);
        example.equals("coinTypeId", coinTypeId);
        example.equals("type", kLineCommon.getType());
        example.setOrderByClause("id DESC");
        List<KLineData> kLineData = getsByExampleWithoutComplete(example);
        return kLineData;
    }

    public KLineDto getKLineDataOne(Integer coinTypeId) {
        KLineDto dto = new KLineDto();
        BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(coinTypeId)));
        dto.setOpenPrice(openPrice);
        BigDecimal gain = coinRatioService.calculateCoinGain(coinTypeId).multiply(new BigDecimal(100));
        dto.setGain(gain);
        BigDecimal todayDealCount = new BigDecimal(jedisUtil.get(RedisKeyCreator.todayDealCount(coinTypeId)));
        dto.setTodayDealCount(todayDealCount);
        BigDecimal highest = new BigDecimal(jedisUtil.get(RedisKeyCreator.coinHighestPrice(coinTypeId)));
        dto.setHighestPrice(highest);
        BigDecimal lowest = new BigDecimal(jedisUtil.get(RedisKeyCreator.coinLowestPrice(coinTypeId)));
        dto.setLowestPrice(lowest);
        return dto;
    }


}
